/*
 * Copyright (c)  2015~2020, xforceplus
 * All rights reserved.
 * Project:datacare-orm
 * Id: LazyMappingEntity.java   2020-10-10 22-16-17
 * Author: Evan
 */
package cn.datacare.orm.mapping.lazy;

import cn.datacare.orm.damoin.Tail;
import cn.datacare.orm.database.ClassDesc;
import cn.datacare.orm.database.TableDesc;
import cn.datacare.orm.manager.Manager;
import cn.datacare.orm.manager.impl.SQLManager;
import cn.datacare.orm.mapping.orm.MappingEntity;
import cn.datacare.orm.util.kit.BeanKit;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: 2015~2020
 * </p>
 * <p>
 * Company/Department: xforceplus
 * </p>
 *
 * @author Evan
 * <b>Creation Time:</b> 2020-10-10 22-16-17
 * @since V1.0
 */
public class LazyMappingEntity extends MappingEntity {

    @Override
    public void map(List list, Manager sm, Map paras) {
        if (list.size() == 0) {
            return;
        }
        init(list.get(0), sm.getEntityLoader());

        for (Object obj : list) {
            mapClassItem(obj, sm, paras);

        }

    }

    @Override
    protected void mapClassItem(final Object obj, final Manager sm, Map sqlParas) {

        final String sqlManagerName = sm.getSQLManagerName();
        if (sqlId != null) {
            final Map<String, Object> paras = new HashMap<>();
            if (sqlParas != null && !sqlParas.isEmpty()) {
                //外部参数，非映射参数
                paras.putAll(sqlParas);
            }
            for (Map.Entry<String, String> entry : this.mapKey.entrySet()) {
                String attr = entry.getKey();
                String targetAttr = entry.getValue();
                Object value = BeanKit.getBeanProperty(obj, attr);
                paras.put(targetAttr, value);

            }

            LazyEntity lazy = (LazyEntity) () -> {
                SQLManager sqlManager = getSQLManager(sqlManagerName);
                List ret = sqlManager.select(sqlId, targetClass, paras);
                return retValue(ret);
            };
            setTailAttr(obj, lazy);

        } else {
            if (mapKey.size() == 1) {
                String tableName = sm.getNameConversion().getTableName(targetClass);
                TableDesc tableDesc = sm.getMetaDataManager().getTable(tableName);
                ClassDesc classDesc = tableDesc.getClassDesc(targetClass, sm.getNameConversion());
                if (classDesc.getIdAttrs().size() == 1 && classDesc.getIdAttrs().containsAll(mapKey.values())) {
                    // 主键查询
                    String foreignAttr = this.mapKey.keySet().iterator().next();
                    final Object value = BeanKit.getBeanProperty(obj, foreignAttr);
                    LazyEntity lazy = (LazyEntity) () -> {
                        SQLManager sqlManager = getSQLManager(sqlManagerName);
                        Object ret = sqlManager.single(targetClass, value);
                        return ret;
                    };
                    setTailAttr(obj, lazy);
                    return;

                }
            }

            final Object ins = getIns(targetClass);
            for (Map.Entry<String, String> entry : this.mapKey.entrySet()) {
                String attr = entry.getKey();
                String targetAttr = entry.getValue();
                Object value = BeanKit.getBeanProperty(obj, attr);
                BeanKit.setBeanProperty(ins, value, targetAttr);

            }
            LazyEntity lazy = (LazyEntity) () -> {
                SQLManager sqlManager = getSQLManager(sqlManagerName);
                List ret = sqlManager.template(ins);
                return retValue(ret);
            };
            setTailAttr(obj, lazy);

        }

    }

    @Override
    protected void setTailAttr(Object o, Object value) {
        //懒加载只能通过tail接口来做了
        if (o instanceof Tail) {
            ((Tail) o).set(tailName, value);
        } else {
            // annotation
            Method m = BeanKit.getTailMethod(o.getClass());
            if (m == null) {
                throw new RuntimeException("懒加载 OR/Mapping 必须实现Tail接口,用于设置 " + tailName + "对象，或者不使用懒加载");
            }
            try {
                m.invoke(o, tailName, value);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }

        }
    }

    private Object retValue(List ret) {
        if (isSingle) {
            if (ret.isEmpty()) {
                return null;
            } else {
                return ret.get(0);
            }

        } else {

            return ret;
        }
    }

    private SQLManager getSQLManager(String name) {
        return SQLManager.getSQLManagerByName(name);
    }
}
